From 1d495cbafd3f3de494e9cf8673103f82982494b6 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Fri, 10 Jan 2014 12:04:17 +0100 Subject: [PATCH] popover: Add a "modal" boolean property to GtkPopover This property is TRUE by default, when a popover is modal, it will automatically set a GTK+ grab on the popover, and grab the keyboard focus into the popover. --- demos/gtk-demo/popover.c | 3 +- docs/reference/gtk/gtk3-sections.txt | 2 + gtk/gtkentry.c | 2 + gtk/gtkpopover.c | 104 ++++++++++++++++++++++++++- gtk/gtkpopover.h | 6 ++ gtk/gtktextview.c | 2 + 6 files changed, 115 insertions(+), 4 deletions(-) diff --git a/demos/gtk-demo/popover.c b/demos/gtk-demo/popover.c index 4247f57606..cb2c6b9765 100644 --- a/demos/gtk-demo/popover.c +++ b/demos/gtk-demo/popover.c @@ -92,7 +92,6 @@ entry_icon_press_cb (GtkEntry *entry, gtk_entry_get_icon_area (entry, icon_pos, &rect); gtk_popover_set_pointing_to (GTK_POPOVER (popover), &rect); gtk_widget_show (popover); - gtk_grab_add (popover); g_object_set_data (G_OBJECT (entry), "popover-icon-pos", GUINT_TO_POINTER (icon_pos)); @@ -126,7 +125,6 @@ day_selected_cb (GtkCalendar *calendar, gtk_popover_set_pointing_to (GTK_POPOVER (popover), &rect); gtk_widget_show (popover); - gtk_grab_add (popover); gdk_event_free (event); } @@ -151,6 +149,7 @@ do_popover (GtkWidget *do_widget) popover = create_popover (widget, gtk_label_new ("This popover does not grab input"), GTK_POS_TOP); + gtk_popover_set_modal (GTK_POPOVER (popover), FALSE); g_signal_connect (widget, "toggled", G_CALLBACK (toggle_changed_cb), popover); gtk_container_add (GTK_CONTAINER (box), widget); diff --git a/docs/reference/gtk/gtk3-sections.txt b/docs/reference/gtk/gtk3-sections.txt index 91f4f484be..d058a85c4b 100644 --- a/docs/reference/gtk/gtk3-sections.txt +++ b/docs/reference/gtk/gtk3-sections.txt @@ -7869,4 +7869,6 @@ gtk_popover_set_pointing_to gtk_popover_get_pointing_to gtk_popover_set_position gtk_popover_get_position +gtk_popover_set_modal +gtk_popover_get_modal diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c index 8ff06fd5c4..90868242a7 100644 --- a/gtk/gtkentry.c +++ b/gtk/gtkentry.c @@ -2674,6 +2674,7 @@ gtk_entry_init (GtkEntry *entry) gtk_widget_set_size_request (priv->magnifier, 100, 60); _gtk_magnifier_set_magnification (GTK_MAGNIFIER (priv->magnifier), 2.0); priv->magnifier_popover = gtk_popover_new (GTK_WIDGET (entry)); + gtk_popover_set_modal (GTK_POPOVER (priv->magnifier_popover), FALSE); gtk_container_add (GTK_CONTAINER (priv->magnifier_popover), priv->magnifier); gtk_container_set_border_width (GTK_CONTAINER (priv->magnifier_popover), 4); @@ -9473,6 +9474,7 @@ bubble_targets_received (GtkClipboard *clipboard, priv->selection_bubble = gtk_popover_new (GTK_WIDGET (entry)); gtk_popover_set_position (GTK_POPOVER (priv->selection_bubble), GTK_POS_TOP); + gtk_popover_set_modal (GTK_POPOVER (priv->selection_bubble), FALSE); toolbar = GTK_WIDGET (gtk_toolbar_new ()); gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_TEXT); diff --git a/gtk/gtkpopover.c b/gtk/gtkpopover.c index e425641ad3..6062dcaf7c 100644 --- a/gtk/gtkpopover.c +++ b/gtk/gtkpopover.c @@ -53,7 +53,8 @@ typedef struct _GtkPopoverPrivate GtkPopoverPrivate; enum { PROP_RELATIVE_TO = 1, PROP_POINTING_TO, - PROP_POSITION + PROP_POSITION, + PROP_MODAL }; struct _GtkPopoverPrivate @@ -68,6 +69,7 @@ struct _GtkPopoverPrivate guint preferred_position : 2; guint final_position : 2; guint current_position : 2; + guint modal : 1; }; static GQuark quark_widget_popovers = 0; @@ -81,13 +83,15 @@ G_DEFINE_TYPE_WITH_PRIVATE (GtkPopover, gtk_popover, GTK_TYPE_BIN) static void gtk_popover_init (GtkPopover *popover) { + GtkPopoverPrivate *priv; GtkWidget *widget; widget = GTK_WIDGET (popover); gtk_widget_set_has_window (widget, TRUE); - popover->priv = gtk_popover_get_instance_private (popover); + popover->priv = priv = gtk_popover_get_instance_private (popover); gtk_style_context_add_class (gtk_widget_get_style_context (widget), GTK_STYLE_CLASS_OSD); + priv->modal = TRUE; } static void @@ -110,6 +114,10 @@ gtk_popover_set_property (GObject *object, gtk_popover_set_position (GTK_POPOVER (object), g_value_get_enum (value)); break; + case PROP_MODAL: + gtk_popover_set_modal (GTK_POPOVER (object), + g_value_get_boolean (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -134,6 +142,9 @@ gtk_popover_get_property (GObject *object, case PROP_POSITION: g_value_set_enum (value, priv->preferred_position); break; + case PROP_MODAL: + g_value_set_boolean (value, priv->modal); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -206,9 +217,18 @@ gtk_popover_realize (GtkWidget *widget) static void gtk_popover_map (GtkWidget *widget) { + GtkPopoverPrivate *priv; + + priv = GTK_POPOVER (widget)->priv; GTK_WIDGET_CLASS (gtk_popover_parent_class)->map (widget); gdk_window_show (gtk_widget_get_window (widget)); gtk_popover_update_position (GTK_POPOVER (widget)); + + if (priv->modal) + { + gtk_grab_add (widget); + gtk_widget_grab_focus (widget); + } } static void @@ -881,6 +901,22 @@ gtk_popover_class_init (GtkPopoverClass *klass) GTK_TYPE_POSITION_TYPE, GTK_POS_TOP, GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + /** + * GtkPopover:modal + * + * Sets whether the popover is modal (so other elements in the window are + * not usable while the popover is visible). + * + * Since: 3.12 + */ + g_object_class_install_property (object_class, + PROP_MODAL, + g_param_spec_boolean ("modal", + P_("Modal"), + P_("Whether the popover is modal"), + TRUE, + GTK_PARAM_READWRITE)); + quark_widget_popovers = g_quark_from_static_string ("gtk-quark-widget-popovers"); } @@ -1240,3 +1276,67 @@ gtk_popover_get_position (GtkPopover *popover) return priv->preferred_position; } + +/** + * gtk_popover_set_modal: + * @popover: a #GtkPopover + * @modal: #TRUE to make popover claim all input within the toplevel + * + * Sets whether @popover is modal, a modal popover will grab all input + * within the toplevel and grab the keyboard focus on it when being + * displayed. Clicking outside the popover area or pressing Esc will + * dismiss the popover and ungrab input. + * + * Since: 3.12 + **/ +void +gtk_popover_set_modal (GtkPopover *popover, + gboolean modal) +{ + GtkPopoverPrivate *priv; + + g_return_if_fail (GTK_IS_POPOVER (popover)); + + priv = popover->priv; + + if ((priv->modal == TRUE) == (modal == TRUE)) + return; + + priv->modal = (modal != FALSE); + + if (gtk_widget_is_visible (GTK_WIDGET (popover))) + { + if (priv->modal) + { + gtk_grab_add (GTK_WIDGET (popover)); + gtk_widget_grab_focus (GTK_WIDGET (popover)); + } + else + gtk_grab_remove (GTK_WIDGET (popover)); + } + + g_object_notify (G_OBJECT (popover), "modal"); +} + +/** + * gtk_popover_get_modal: + * @popover: a #GtkPopover + * + * Returns whether the popover is modal, see gtk_popover_set_modal to + * see the implications of this. + * + * Returns: #TRUE if @popover is modal + * + * Since: 3.12 + **/ +gboolean +gtk_popover_get_modal (GtkPopover *popover) +{ + GtkPopoverPrivate *priv; + + g_return_val_if_fail (GTK_IS_POPOVER (popover), FALSE); + + priv = popover->priv; + + return priv->modal; +} diff --git a/gtk/gtkpopover.h b/gtk/gtkpopover.h index 231dcb0fe1..37b0655337 100644 --- a/gtk/gtkpopover.h +++ b/gtk/gtkpopover.h @@ -73,6 +73,12 @@ void gtk_popover_set_position (GtkPopover *popover, GDK_AVAILABLE_IN_3_12 GtkPositionType gtk_popover_get_position (GtkPopover *popover); +GDK_AVAILABLE_IN_3_12 +void gtk_popover_set_modal (GtkPopover *popover, + gboolean modal); +GDK_AVAILABLE_IN_3_12 +gboolean gtk_popover_get_modal (GtkPopover *popover); + G_END_DECLS #endif /* __GTK_POPOVER_H__ */ diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c index 1fa6945095..0ec8319903 100644 --- a/gtk/gtktextview.c +++ b/gtk/gtktextview.c @@ -1551,6 +1551,7 @@ gtk_text_view_init (GtkTextView *text_view) gtk_widget_set_size_request (priv->magnifier, 100, 60); _gtk_magnifier_set_magnification (GTK_MAGNIFIER (priv->magnifier), 2.0); priv->magnifier_popover = gtk_popover_new (widget); + gtk_popover_set_modal (GTK_POPOVER (priv->magnifier_popover), FALSE); gtk_container_add (GTK_CONTAINER (priv->magnifier_popover), priv->magnifier); gtk_container_set_border_width (GTK_CONTAINER (priv->magnifier_popover), 4); @@ -8947,6 +8948,7 @@ bubble_targets_received (GtkClipboard *clipboard, priv->selection_bubble = gtk_popover_new (GTK_WIDGET (text_view)); gtk_popover_set_position (GTK_POPOVER (priv->selection_bubble), GTK_POS_TOP); + gtk_popover_set_modal (GTK_POPOVER (priv->selection_bubble), FALSE); toolbar = GTK_WIDGET (gtk_toolbar_new ()); gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_TEXT); -- 2.30.2